module adr_gen_sequential
#( 
  parameter BANK_ADDR_WIDTH = 32
)(
  input clk,
  input rst_n,
  input adr_en,
  output [BANK_ADDR_WIDTH - 1 : 0] adr,
  input config_en,
  input [BANK_ADDR_WIDTH - 1 : 0] config_data
);

  reg [BANK_ADDR_WIDTH - 1 : 0] config_block_max;

  // This is a common sequential address generator, reused with input write,
  // weight write, weight read, output write, output read and output read for
  // writeback address generators. The only difference is what the
  // config_block_max would be set to in each case. config_block_max is the
  // maximum address generated by the address generator (the last address for
  // the block/tile of data), after that it goes back to 0. So the sequence of
  // addresses would be: 0, 1, 2, ..., config_block_max, 0, 1, 2 and so on.
 
  // You need to generate the adr output, but make sure you increment/step the
  // address generator only when adr_en is high. Also reset all registers when
  // rst_n is low. When config_en is high, store the value on config_data into
  // config_block_max (this is done initially to configure the address
  // generator to generate the desired sequence, before starting the
  // convolution).

  // Your code starts here
  wire last_adr_w;

  always @ (posedge clk) begin
    if (rst_n) begin
      if (config_en) begin
        config_block_max <= config_data; 
      end
    end else begin
      config_block_max <= 0;
    end
  end
  
  reg [BANK_ADDR_WIDTH - 1 : 0] adr_r;
  
  always @ (posedge clk) begin
    if (rst_n) begin
      if (adr_en) begin
        adr_r <= last_adr_w ? 0 : adr_r + 1;
      end
    end else begin
      adr_r <= 0;
    end
  end

  assign adr = adr_r;
  assign last_adr_w = (adr_r == config_block_max);
  // Your code ends here
endmodule
